﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JtextEpicsInterface;
using System.Text.RegularExpressions;
using PSIEpics;
using jtext_EpicsClient;
using System.Collections;

namespace JeSequencer
{
    //2012/02/09
    //add noMonitortMode
    //allow change state manually ,but must affter the plugin has been run once
    //1.3.0.0

    /// <summary>
    /// a sequencer plugin for jtext epics 
    /// </summary>
    public class JsmPlugIn : IJEPlugIn
    {

        #region StateMacnhine

        StateMachine Sm;
        JECLient myClient;
        bool noMonitorMode;
        bool isFirstRun;
        #endregion
        //Record will call this in a full flush between of flush flush2 
        /// <summary>
        /// Gets the name of the plug in.
        /// <para>plaese use a const and hard code it </para>
        /// </summary>
        /// <value>
        /// The name of the plug in.read only
        /// </value>
        public string PlugInName
        {
            get
            {
                return "JsmPlugIn";
            }
        }

        /// <summary>
        /// Initialize the plug in.
        /// <para>This is call onec at the beginning for the server start up,and the record is not going to initialize any thing later so finish all the initialize job.
        /// <para>like drvier you normally need some parameter,so use a gonfig file for this job</para>
        /// </summary>
        /// <param name="iniObject">Not used.</param>
        public void IniPlugIn(object iniObject, IJERecord record)
        {
            myClient = new JECLient();
            string StrConfig = (string)iniObject;//hi lo rate,ini_value
            string[] StrConfigs = Regex.Split(StrConfig, ";", RegexOptions.IgnoreCase);
            int Config_index = StrConfig.IndexOf("JsmPlugIn") + 1;
            string smName = StrConfigs[Config_index + 0];
            string JsmXmlPath = AppDomain.CurrentDomain.BaseDirectory.ToString() + "Jsm//" + smName;
            Sm = StateMachine.OpenFromFile(JsmXmlPath);
            if (StrConfigs[Config_index + 1] == "NoMonitor")
            {
                noMonitorMode = true;
                Console.WriteLine("No Monitor Mode.");
            }
            else
            {
                noMonitorMode = false;
            }
            //epics

            foreach (object Pv in Sm.InputlistKey)
            {
                if (Pv.ToString() != StateMachine.LIVETIME)
                {
                    myClient.AddChannel<ExtTimeType<string>>(Pv.ToString());
                    if (noMonitorMode == false)
                    {
                        myClient[Pv.ToString()].MonitorMask = MonitorMask.ALL;
                        ((EpicsChannel<ExtTimeType<string>>)myClient[Pv.ToString()]).MonitorChanged += new EpicsDelegate<ExtTimeType<string>>(ChageInput);
                    }
                }
            }


            isFirstRun = true;
            Sm.Start();
            Console.WriteLine("Jsm init: Current State: " + Sm.CurrentState.ToString());
            //To do, try not use monitor
            //two ways add a scan thread of change input right before changing state

        }

        /// <summary>
        /// Runs the plug in.
        /// <Para>the record will call this each time it get flushed,for input and out put there  maybe differences.Look up example if you are making plugin</Para>
        /// </summary>
        /// <param name="myRecord">My record.The record that called the plugIn,you can set get and do anything</param>
        /// <returns>if successful</returns>
        public bool RunPlugIn(IJERecord myRecord)
        {
            if (isFirstRun == false)
            {
                if (Sm.CurrentState != ((int)(myRecord.PVAL)))
                {
                    if (Sm.MyStates.containState(((int)(myRecord.PVAL))))
                    {
                        Sm.CurrentState = ((int)(myRecord.PVAL));
                        Sm.inputChanged();
                    }
                }
            }
            else
            {
                myRecord.PVAL = Sm.CurrentState;
            }
            if (noMonitorMode == true)
            {
                changeInputWithoutMonitor();
            }
            Sm.UpdateState();
            myRecord.VAL = Sm.CurrentState;
            isFirstRun = false;
            return true;
        }


        /// <summary>
        /// Kills the plug in when you don't need it.
        /// </summary>
        public void KillPlugIn()
        {
            myClient.DisposeAll();
        }

        private void ChageInput(EpicsChannel sender, object newValue)
        {
            //change the input list in statemachine
            ExtTimeType<string> Trecod;
            Trecod = (ExtTimeType<string>)newValue;
            Sm.InputList[sender.ChannelName] = Trecod.Value.ToString();
            Sm.inputChanged();
        }

        private void changeInputWithoutMonitor()
        {
            foreach (object Pv in Sm.InputlistKey)
            {
                if (Pv.ToString() != StateMachine.LIVETIME)
                {
                    try
                    {
                        Sm.InputList[Pv.ToString()] = (myClient.RecordVAL[Pv.ToString()]).ToString();
                    }
                    catch
                    { }
                }
            }
            Sm.inputChanged();

        }





    }
}
